package com.gzdh.device.security;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;

import com.gzdh.device.comm.util.ResponseUtil;
import com.gzdh.device.comm.vo.Result;
import com.gzdh.device.config.TokenManager;
import com.gzdh.device.system.dto.SysUserDetailsDTO;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;

import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

/**
 * 自定义认证过滤器
 *
 * @author
 */
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
    /**
     * 生成得到token的对象
     */
    private TokenManager tokenManager;
    /**
     * redis模板操作redis
     */
    private RedisTemplate redisTemplate;
    /**
     * 权限管理工具 springSecurity自带的
     */
    private AuthenticationManager authenticationManager;

    public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisTemplate redisTemplate) {
        this.authenticationManager = authenticationManager;
        this.tokenManager = tokenManager;
        this.redisTemplate = redisTemplate;
        this.setPostOnly(false);
        //设置登录路径和提交方式,也可以再配置类中设置
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/gzdh/admin/login", "POST"));
    }

    /**
     * 1 获取表单提交用户名和密码
     *
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {

        String userName = "";
        String password = "";
        try {
            ServletInputStream requestInputStream = request.getInputStream();
            //将字节流转换为字符流,并设置字符编码为utf-8
            InputStreamReader ir = new InputStreamReader(requestInputStream, "utf-8");
            //使用字符缓冲流进行读取
            BufferedReader br = new BufferedReader(ir);
            //开始拼装json字符串
            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            JSONObject json = JSONObject.parseObject(sb.toString());
            userName = json.getString("username");
            password = json.getString("password");
        } catch (Exception e) {
            e.printStackTrace();
        }

        return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userName, password));
    }

    //2 认证成功调用的方法
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain, Authentication authResult)
            throws IOException, ServletException {
        //认证成功，得到认证成功之后用户信息
        SysUserDetailsDTO user = (SysUserDetailsDTO) authResult.getPrincipal();
        //根据用户名生成token
        String token = tokenManager.createToken(user.getUsername());
        //把 用户名称 和用户权限列表 放到redis
        System.out.println(user.toString());
        redisTemplate.opsForValue().set("sys:userrole:" + user.getUsername(), JSONArray.toJSONString(user.getPerms()));
        //返回token
        Result<Object> result = new Result<>();
        result.setResult(token);
        ResponseUtil.out(response, result);
    }

    @Override
    //3 认证失败调用的方法
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed)
            throws IOException, ServletException {

        ResponseUtil.out(response, Result.error("登陆失败,请核对用户名或密码"));
    }
}

